import WatchGradualNumber from '@/utils/WatchGradualNumber';
import WatchNumber from '@/utils/WatchNumber';

export type WatchType = WatchGradualNumber | WatchNumber | WatchValue<any>;

/** 保存的触发数据 */
export interface SaveEmit {
	/** 绑定对象 */
	target: any;
	/** 深度绑定 */
	deep: boolean;
	/** 内容变更的触发事件 */
	event: () => void;
}

/**
 * 数据变化监视类
 * @template T 被监视的数据类型
 */
export default class WatchValue<T>{

	/** 保存的内容 */
	private value!: T;

	/** 内容变更触发列表 */
	private emitList2: Map<any, Set<SaveEmit>> = new Map();

	/** 内容 */
	public get Value(): T {
		return this.value;
	}
	public set Value(val: T) {
		const change = this.value !== val;
		this.value = val;
		this.Trigger(change);
	}

	/**
	 * 构造函数
	 * @param value 绑定 内容/监视类/公式
	 * @param list 公式所需的监视列表(可选)
	 */
	public constructor(value: T | WatchValue<T> | string | ((...list: WatchType[]) => T), ...list: WatchType[]) {
		if (value instanceof WatchValue) {
			this.Bind(value);
		} else if (typeof (value) === "string") {
			if (list.length > 0) {
				WatchValue.Eval(this, value, ...list);
			} else {
				this.value = value as T;
			}
		} else if (typeof (value) === "function") {
			if (list.length > 0) {
				WatchValue.BindCall(this, value as any, ...list);
			} else {
				this.value = value as T;
			}
		} else {
			this.value = value;
		}
	}

	/**
	 * 数据更新触发
	 * @param change 数据源是否变更
	 */
	public Trigger(change?: boolean): void {
		this.emitList2.forEach((list) => {
			list.forEach(({ deep, event }) => {
				if (change || (!change && deep)) {
					event();
				}
			});
		});
	}

	/** 清除绑定的触发 */
	public Clear(): void {
		this.emitList2 = new Map();
	}

	/**
	 * 清除指定对象的绑定事件
	 * @param target 被清除的对象
	 */
	public ClearTarget(target: any): void {
		this.emitList2.delete(target);
	}

	/**
	 * 添加数据变化事件
	 * @param target 绑定对象
	 * @param event 绑定事件
	 * @param deep 是否未深度绑定
	 */
	public Add(target: any, event: () => (T | void), deep: boolean = false): void {
		if (!this.emitList2.has(target)) {
			this.emitList2.set(target, new Set());
		}
		(this.emitList2.get(target) as Set<SaveEmit>).add({ target, event, deep });
	}

	/**
	 * 监视数据
	 * @param target 被监视的数据
	 * @param deep 是否未深度绑定
	 */
	public Bind(target: WatchValue<T>, deep: boolean = false): void {
		this.Value = target.Value;
		target.Add(this as any, () => this.Value = target.value, deep);
	}

	/**
	 * 监视文本公式
	 * @param str 文本公式
	 * @param list 被监视列表
	 */
	public BindEval(str: string, ...list: WatchType[]): void {
		WatchValue.Eval(this, str, ...list);
	}

	/**
	 * 监视回调函数
	 * @param backcall 监视回调函数
	 * @param list 被监视列表
	 */
	public BindCall(backcall: (...list: WatchType[]) => T, ...list: WatchType[]): void {
		return WatchValue.BindCall(this, backcall, ...list);
	}

	/**
	 * 深度监视回调函数
	 * @param backcall 监视回调函数
	 * @param list 被监视列表
	 */
	public DeepBindCall(backcall: () => T, father: WatchType, childcall: () => WatchType | null): void {
		this.BindCall(backcall, father);
		father.Add(null, () => {
			const child = childcall();
			if (child !== null) {
				this.BindCall(backcall, child)
			}
		});
	}

	/**
	 * 监视文本公式
	 * @param target 绑定监视结果的对象
	 * @param str 文本公式
	 * @param list 被监视列表
	 */
	public static Eval<T>(target: WatchValue<T>, str: string, ...list: WatchType[]): void {
		const res = str.split(/\#\{(.*?)\}/);
		const calc = () => eval(res.map((item, j) => j % 2 === 1 ? `list[${item}].Value` : item).join(""));
		target.Value = calc();
		for (let i = 1; i < res.length; i += 2) {
			const temp: WatchValue<T> = eval(`list[${res[i]}]`);
			temp.Add(target, calc);
		}
	}

	/**
	 * 监视回调函数
	 * @param target 绑定监视结果的对象
	 * @param str 监视结果回调函数
	 * @param list 被监视列表
	 */
	public static BindCall<T>(target: WatchValue<T>, backcall: (...list: WatchType[]) => T, ...list: WatchType[]): void {
		const calc = () => target.Value = backcall(...list);
		calc();
		list.forEach(item => item && item.Add(target, calc));
	}
}
